package app.agent;

import app.env.Data;
import app.tasks.SearchTask;
import app.tasks.schedule.*;
import app.env.Position;
import app.env.ShowGui;
import app.util.algo.DirectTA;
import framework.agent.CustomAgent;
import framework.task.Task;
import framework.task.TaskContainer;
import jade.core.*;
import jade.core.Runtime;
import jade.core.behaviours.FSMBehaviour;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
import jade.wrapper.StaleProxyException;

import java.util.*;

/**
 * @Name: Admin
 * @Description: 执行遗传算法的初始化种群，淘汰个体，以及生成新的个体的部分。
 * 该代理通过Jade的Directory Facilitator创建和销毁别的代理。在接收到搜索代
 * 理的数据之后，计算所有个体的适应度，并将小于适应度平均值的个体淘汰掉。并重新
 * 初始化淘汰个体数目的新的Agent。
 * @Author: colfish
 * @Date: 2021/3/27
 * 好好学习，天天向上！
 */
public class Schedule extends CustomAgent {

    private static final long serialVersionUID = -3225068739440173133L;

    public static AID IDENTIFIER = new AID("Admin", AID.ISLOCALNAME);

    public static int searchRange = Data.SEARCH_RANGE;

    public static int targetDetectRange = searchRange;
    

    // 接收搜索代理信号的次数
    public int receiveCount = 0;
    // 临时存储目标代理位置
    public Position tempTarPos = new Position();
    // 临时存储发送消息的搜索代理名称
    public AID tempSearchAID;

    // 行为种类
    private static final String init = "init";
    private static final String waitSignal = "waitSignal";
    private static final String dealFindTarget = "dealFindTarget";
    private static final String sortSend = "sortAndSend";
    private static final String stopSearch = "stopSearch";
    private static final String end = "end";

    
    @Override
    protected void setup() {
        FSMBehaviour behaviour = new FSMBehaviour(this);
        //States
        behaviour.registerFirstState(new Init(this), init);
        behaviour.registerState(new WaitMessage(this), waitSignal);
        behaviour.registerState(new DealFindTarget(this), dealFindTarget);
        behaviour.registerState(new SortSend(this), sortSend);
        behaviour.registerState(new StopSearch(this), stopSearch);
        behaviour.registerLastState(new End(this), end);

        //Transitions
        // init
        behaviour.registerDefaultTransition(init, waitSignal);

        // WaitSignal
        behaviour.registerDefaultTransition(waitSignal, waitSignal);
        behaviour.registerTransition(waitSignal, waitSignal, 1);
        behaviour.registerTransition(waitSignal, dealFindTarget, 2);
        behaviour.registerTransition(waitSignal, sortSend, 3);
        behaviour.registerTransition(waitSignal, stopSearch, 4);
        behaviour.registerTransition(waitSignal, end, 0);

        // DealFindTarget
        behaviour.registerDefaultTransition(dealFindTarget, waitSignal);

        // SortSignal
        behaviour.registerDefaultTransition(sortSend,waitSignal);
        behaviour.registerTransition(sortSend,waitSignal,1);

        // StopSearch
        behaviour.registerDefaultTransition(stopSearch, end);

        addBehaviour(behaviour);

    }

        public void initPopulation(int totalNums){
        Runtime runtime = Runtime.instance();
        Profile config = new ProfileImpl("localhost", 8888, "SearchAgents");
        AgentContainer searchContainer = runtime.createAgentContainer(config);
        Random random = new Random();
        for(int i = 0; i < totalNums; i++){
            try {
                /*
                 随机找到totalNums个x坐标处于[range,height-range],y坐标处于[range,width-range]的坐标点
                 并在坐标点初始化SearchAgent
                 坐标点位置信号不等于100000和-100000
                 */
                int height = 200;
                int x = random.nextInt(height -2*searchRange) + searchRange;
                int width = 200;
                int y = random.nextInt(width -2*searchRange) + searchRange;
                // 若新生成坐标对应的Gui中board数据不在正常的信号范围内，则重新生成坐标
                /*
                若新生成坐标对应ShowGui中board数组数据是代理类型的数据，即数据小于0或大于2000，则重新生成坐标
                 */
                if(ShowGui.board[x][y]<0||ShowGui.board[x][y]>2000){
                    i--;
                    continue;
                }
                Position newPos = new Position(x, y);
                // 否则将该位置坐标数据设置为100001;并刷新Gui
                ShowGui.board[x][y] = Data.SEARCH_SIGNAL;
                ShowGui.updateGui();
                // 暂定只有一个参数，存储代理位置
                Object[] args = {newPos};
                AgentController searchController = searchContainer.createNewAgent("searchAgent_"+i, SearchAgent.class.getName(),args);
                Data.agentControllers.put("searchAgent_"+i, searchController);
                Data.searchAgentPositions.put("searchAgent_"+i, newPos);
                searchController.start();



            } catch (StaleProxyException e) {
                e.printStackTrace();
            }
        }

        DirectTA directTA = new DirectTA();
        List<Task> tasks = TaskContainer.createTaskInstance(SearchTask.class.getName(), totalNums);
        directTA.TaskAssign(Data.searchAgents, tasks);
    }

}
